package com.wyw.function.learning.demo6;

import com.wyw.function.learning.common.*;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Title   用流收集数据
 * @Description
 * @Author Mr Wu yewen.wu.china@gmail.com
 * Update History:
 * Author        Time            Content
 */
public class DemoClient13 {

    /**
     * collect收集器
     *      对一个交易列表按货币分组，获得该货币的所有交易额总和（返回一个Map<Currency, Integer）
     *      将交易列表分成两组，贵的和不贵的（返回一个Map<Boolean, List<Transaction）
     *      创建多级分组，比如按城市对交易分组，然后进一步按照贵或不贵分组（返回一个Map<Boolean, List<Transaction>>）
     *  不使用Lambda
     */
//    public static void main(String[] args) {
//        // 把列表中的交易按货币分组
//        List<Transaction1> transactions = TransactionClient.getTransactions();
//        HashMap<Currency, List<Transaction1>> hashMap = new HashMap<>();
//
//        // 遍历 transactions
//        for (Transaction1 transaction: transactions) {
//            // 获取 currency
//            Currency currency = transaction.getCurrency();
//
//            // 获取currency -> List<Transaction>
//            List<Transaction1> list = hashMap.get(currency);
//
//            // 如果为 null 则新建
//            if(list == null) {
//                list = new ArrayList<>();
//                hashMap.put(currency, list);
//            }
//
//            // 增加
//            list.add(transaction);
//
//        }
//        System.out.println(hashMap);
//    }

    /**
     * collect收集器
     *  把列表中的交易按货币分组    使用Lambda
     *
     *      主要提供三大功能：
     *          将流元素规约和汇总为一个值
     *          元素分组
     *          元素分区
     */
//    public static void main(String[] args) {
//        // 把列表中的交易按货币分组
//        List<Transaction1> transactions = TransactionClient.getTransactions();
//        // 可以看出收集器用作高级归约，可以更简洁、灵活的方式定义收集集合的标准
//        Map<Currency, List<Transaction1>> hashMap = transactions.stream().collect(Collectors.groupingBy(Transaction1::getCurrency));
//
//        System.out.println(hashMap);
//    }

    /**
     * 规约和汇总
     *  返回菜单中多少菜
     */
//    public static void main(String[] args) {
//        List<Dish> menu = DishClient.getMenu();
//        Long collect = menu.stream().collect(Collectors.counting());
//        Long collect1 = menu.stream().count();
//        System.out.println(collect);
//        System.out.println(collect1);
//    }

    /**
     * 规约和汇总
     *  查找流中的最大值和最小值
     */
//    public static void main(String[] args) {
//        List<Dish> menu = DishClient.getMenu();
//        Optional<Dish> max = menu.stream().collect(Collectors.maxBy(Comparator.comparing(Dish::getCalories)));
//        Optional<Dish> max1 = menu.stream().max(Comparator.comparing(Dish::getCalories));
//        Optional<Dish> min = menu.stream().collect(Collectors.minBy(Comparator.comparing(Dish::getCalories)));
//        Optional<Dish> min1 = menu.stream().min(Comparator.comparing(Dish::getCalories));
//        System.out.println(max);
//        System.out.println(max1);
//        System.out.println(min);
//        System.out.println(min1);
//    }

    /**
     * 规约和汇总
     *  汇总  Collectors.summingInt
     */
//    public static void main(String[] args) {
//        List<Dish> menu = DishClient.getMenu();
//        // 汇总总热量
//        Integer collect = menu.stream().collect(Collectors.summingInt(Dish::getCalories));
//        Integer collect1 = menu.stream().mapToInt(Dish::getCalories).sum();
//        System.out.println(collect);
//        System.out.println(collect1);
//
//        // 平均值
//        Double collect2 = menu.stream().collect(Collectors.averagingInt(Dish::getCalories));
//        System.out.println(collect2);
//
//        // 一次计算
//        IntSummaryStatistics statistics = menu.stream().collect(Collectors.summarizingInt(Dish::getCalories));
//        long sum = statistics.getSum();
//        int max = statistics.getMax();
//        System.out.println(sum);
//        System.out.println(max);
//    }

    /**
     * 规约和汇总
     *  连接字符串
     */
//    public static void main(String[] args) {
//        List<Dish> menu = DishClient.getMenu();
//        String collect = menu.stream().map(Dish::getName).collect(Collectors.joining());
//        String collect1 = menu.stream().map(Dish::getName).collect(Collectors.joining(", "));
//        System.out.println(collect);
//        System.out.println(collect1);
//    }

    /**
     * 上述的收集器都是一个可以用reducing工厂方法定义的规约过程的特殊情况
     * Collectors.reducing工厂方法是所有特殊情况的一般化
     *      Stream接口的collect和reduce方法的不同
     *          语义问题和实际问题：语义问题在于，reduce方法旨在把两个值结合起来生成一个新值，是一个不可变的规约；collect方法的设计就是要改变容器，从而累计要输出的结果
     */
    public static void main(String[] args) {
        List<Dish> menu = DishClient.getMenu();
        Integer collect = menu.stream()
                .collect(// 收集器
                        Collectors.reducing(
                                0, // 初始值
                                Dish::getCalories, // 待收集的数据
                                (i, j) -> i + j));// 待收集的策略
        System.out.println(collect);

        // 单参形式
        Optional<Dish> collect1 = menu.stream().collect(Collectors.reducing((d1, d2) -> d1.getCalories() > d2.getCalories() ? d1 : d2));
        System.out.println(collect1);
    }

}
